/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package jps_s10996_s7175;

import edu.pjwstk.jps.interpreter.envs.IENVSBinder;
import edu.pjwstk.jps.result.ISingleResult;
import java.util.LinkedList;
import jps_s10996_s7175.envs.ENVS;
import jps_s10996_s7175.envs.ENVSFrame;
import jps_s10996_s7175.objects.SBAStore;
import jps_s10996_s7175.objects.StringObject;
import jps_s10996_s7175.result.BagResult;
import jps_s10996_s7175.result.IntegerResult;
import jps_s10996_s7175.result.QResStack;
import jps_s10996_s7175.result.ReferenceResult;
import jps_s10996_s7175.result.StringResult;

/**
 *
 * @author
 */
public class MiniProjekt04 {

    public static void nowak_married(SBAStore dbstore) {
        QResStack qres = new QResStack();
        ENVS envs = new ENVS();

        envs.init(dbstore.getEntryOID(), dbstore);
        BagResult leftRes = new BagResult();
        BagResult rightRes = new BagResult();

        // wybierz tych ktorzy sa w zwiazku malzenskim oraz tych (unia) ktorzy maja na nazwisko Nowak
        // pokaz ich imiona
        //
        //  emp where lastName = Nowak
        //
        qres.push(new StringResult("lName"));
        qres.push(new StringResult("Nowak"));

        StringResult right = (StringResult) qres.pop();
        StringResult left = (StringResult) qres.pop();

        qres.push((BagResult) envs.bind("emp"));

        for (ISingleResult s : ((BagResult) qres.pop()).getElements()) {
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();

            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));

            qres.push((BagResult) envs.bind(left.getValue()));
            BagResult b = (BagResult) qres.pop();

            ReferenceResult ss = (ReferenceResult) s;
            for (ISingleResult ref : b.getElements()) {
                ReferenceResult ref2 = (ReferenceResult) ref;
                if (dbstore.hasElementAChild(ss.getOIDValue(), ref2.getOIDValue())) {

                    StringObject obj = (StringObject) dbstore.retrieve(ref2.getOIDValue());
                    if (obj.getValue().equals(right.getValue())) {
                        rightRes.add(s);
                    }

                }
            }
            envs.pop();
        }
        qres.push(rightRes);

        //
        //  emp where married
        //
        qres.push(new StringResult("emp"));
        qres.push(new StringResult("married"));

        right = (StringResult) qres.pop();
        left = (StringResult) qres.pop();

        qres.push((BagResult) envs.bind(left.getValue()));

        for (ISingleResult s : ((BagResult) qres.pop()).getElements()) {
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();

            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));

            qres.push((BagResult) envs.bind(right.getValue()));
            BagResult b = (BagResult) qres.pop();

            ReferenceResult ss = (ReferenceResult) s;
            for (ISingleResult ref : b.getElements()) {
                ReferenceResult ref2 = (ReferenceResult) ref;
                //where exists

                LinkedList<IENVSBinder> listElemEmp = new LinkedList<IENVSBinder>();

                // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
                listElemEmp.addAll(envs.nested(s, dbstore).getElements());
                envs.push(new ENVSFrame(listElemEmp));

                if (dbstore.hasElementAChild(ss.getOIDValue(), ref2.getOIDValue())) {

                    //where true   
                    StringObject married = (StringObject) dbstore.retrieve(ref2.getOIDValue());
                    if (married.getValue().equals("true")) {
                        leftRes.add(s);
                    }
                }

                envs.pop();
            }
            envs.pop();
        }

        qres.push(leftRes);

        rightRes = (BagResult) qres.pop();
        leftRes = (BagResult) qres.pop();

        // union
        BagResult union = new BagResult();

        for (ISingleResult u1 : rightRes.getElements()) {
            union.add(u1);
        }

        for (ISingleResult u1 : leftRes.getElements()) {
            union.add(u1);
        }

        System.out.println("emp where married union lname Nowak\n\t" + union.stringme());

        qres.push(union);
        qres.push(new StringResult("fName"));

        StringResult rightL = (StringResult) qres.pop();
        BagResult leftL = (BagResult) qres.pop();

        BagResult final_res = new BagResult();

        for (ISingleResult s : leftL.getElements()) {
            // 3.1. Utworzyć nową sekcję na ENVS
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();

            // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));

            // 3.3. Wykonać eval(q2) i zrobić q2res = QRES.POP()
            qres.push((BagResult) envs.bind(rightL.getValue()));
            BagResult b = (BagResult) qres.pop();

            // 3.5. Zamknąć sekcję ENVS
            envs.pop();

            // 4. Zrobić QRES.PUSH(dotres)
            final_res.add(b);

        }
        System.out.println("emp where married union lname Nowak fname\n\t" + final_res.stringme());
    }

    public static void address_number(SBAStore dbstore) {
        //((emp where exists address) where address.number>20).(street, city)
        QResStack qres = new QResStack();
        ENVS envs = new ENVS();
        
        envs.init(dbstore.getEntryOID(), dbstore);
        BagResult bagEMP = (BagResult)envs.bind("emp");
        BagResult finalResult = new BagResult();
        //System.out.println(bagEMP.stringme());
        qres.push(bagEMP);
        
        for (ISingleResult singleResult : ((BagResult) qres.pop()).getElements()) {//emp where exists address
            envs.push(envs.nested(singleResult, dbstore));
            qres.push((BagResult)envs.bind("address"));//where address exists
            for(ISingleResult singleAddres : ((BagResult) qres.pop()).getElements()) {
                envs.push(envs.nested(singleAddres, dbstore));
                qres.push((BagResult)envs.bind("number")); //bierzemy number
                qres.push(new IntegerResult(new Integer(20))); //pushujemy 20 jako ze number w adresie ma byc wiekszy od 20
                
                Integer liczbaDoPorownania = ((IntegerResult)qres.pop()).getValue(); //pop na qres
                for (ISingleResult a : ((BagResult)qres.pop()).getElements()){ //pop na qres ->tu mamy baga z numerem z xml, dla danego adresu
                    //System.out.println(((ReferenceResult)a).getOIDValue());
                    StringObject obj = (StringObject) dbstore.retrieve(((ReferenceResult)a).getOIDValue()); //z bazy wyciagamy wartosc numeru
                    if(liczbaDoPorownania < Integer.parseInt(obj.getValue())){ //jezeli numer jest wiekszy niz 20 znajdujemy w envs identyfikatory dla ulicy i miasta
                        //System.out.println(((BagResult)envs.bind("street")).stringme());
                        //System.out.println(((BagResult)envs.bind("city")).stringme());
                        BagResult bagCityStreet = new BagResult();
                        bagCityStreet.add((BagResult)envs.bind("street"));
                        bagCityStreet.add((BagResult)envs.bind("city"));
                        finalResult.add(
                            bagCityStreet
                        );
                    }
                    
                }
                envs.pop();
            }
            envs.pop();
        }
        //System.out.println(qres);
        System.out.println("((emp where exists address) where address.number>20).(street, city)\n" + finalResult.stringme());
    }

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    public static void dot_operator(SBAStore dbstore) {
        QResStack qres = new QResStack();
        ENVS envs = new ENVS();

        // 1. Zainicjalizować dotres = bag()
        envs.init(dbstore.getEntryOID(), dbstore);

        BagResult dotres = new BagResult();

        // 2. Wykonać eval(q1) i zrobić q1res = QRES.POP()
        qres.push((BagResult) envs.bind("emp"));

        // 3. Dla każdego elementu x ze zbioru q1res wykonać:
        for (ISingleResult s : ((BagResult) qres.pop()).getElements()) {
            // 3.1. Utworzyć nową sekcję na ENVS
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();

            // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));

            // 3.3. Wykonać eval(q2) i zrobić q2res = QRES.POP()
            qres.push((BagResult) envs.bind("lName"));
            BagResult b = (BagResult) qres.pop();

            // 3.5. Zamknąć sekcję ENVS
            envs.pop();

            // 4. Zrobić QRES.PUSH(dotres)
            dotres.add(b);

        }

        System.out.println(dotres.stringme());
    }

    public static void where_operator(SBAStore dbstore) {
        QResStack qres = new QResStack();
        ENVS envs = new ENVS();

        // 1. Zainicjalizować dotres = bag()
        envs.init(dbstore.getEntryOID(), dbstore);

        BagResult dotres = new BagResult();

        // 2. Wykonać eval(q1) i zrobić q1res = QRES.POP()
        qres.push((BagResult) envs.bind("emp"));

        // 3. Dla każdego elementu x ze zbioru q1res wykonać:
        for (ISingleResult s : ((BagResult) qres.pop()).getElements()) {
            // 3.1. Utworzyć nową sekcję na ENVS
            LinkedList<IENVSBinder> list = new LinkedList<IENVSBinder>();

            // 3.2. Wykonać nested(x). Wynik wprowadzić do sekcji utworzonej w poprzednim kroku
            list.addAll(envs.nested(s, dbstore).getElements());
            envs.push(new ENVSFrame(list));

            // 3.3. Wykonać eval(q2) i zrobić q2res = QRES.POP()
            qres.push((BagResult) envs.bind("married"));
            BagResult b = (BagResult) qres.pop();

            // 3.4. Jeżeli q2res wynosi true dodać x do whereres
            if (b.getElements().size() > 0) {
                dotres.add(b);
                //poprawione nizej
            }

            // 3.5. Zamknąć sekcję ENVS
            envs.pop();
        }

        System.out.println(dotres.stringme());
    }
}
